/*
 * ***************************************************************************************************
 * TestHashing.h ($RCSfile: $)
 *
 * Test harness for testing and debugging the WaMM Hash Algorithm
 *
 * Copyright 2008 John Washburn.  All rights reserved until I win the SHA3 contest.
 *
 *
 * ***************************************************************************************************

$Header: $

$Revision: $

$Log: $

 *
 */

#include <string.h>
#include <time.h>
#include "TestHashing.h"

BOOL TestZeroBitMessages(void);
BOOL TestRepeatedHashing(void);
BOOL HashGigabyte(void);
BOOL HashFile(void);

BOOL TestHashing()
{
	BOOL bStatus = FALSE;

//	bStatus = TestZeroBitMessages();
	printf("TestZeroBitMessages() %s.\n\f", (bStatus? "passed" : "FAILED"));

//	bStatus = TestRepeatedHashing();
	printf("TestRepeatedHashing() %s.\n\f", (bStatus? "passed" : "FAILED"));

//	bStatus = HashGigabyte();
	printf("HashGigabyte() %s.\n\f", (bStatus? "passed" : "FAILED"));

	bStatus = HashFile();
	printf("HashGigabyte() %s.\n\f", (bStatus? "passed" : "FAILED"));

	return bStatus;
}

BOOL HashFile()
{
	HashReturn retVal = FAIL;
	hashState State;
	BitSequence HashValue[WaMM_HashLen_MaxBytes];

	BitSequence *pOneMegabyte = NULL;
	clock_t clockStart;
	clock_t clockEnd;
	clock_t clockDiff;
	FILE *InputFile = NULL; 
	const long  lMegabyte = 0x01000000;
	long lNumBytesRead;
	long lNumBitsRead;
	long long llTotalBitsHashed;
	char szFileName[] = "H:\\Programming\\WaMM\\ReferenceImplementation\\WaMM\\OneGigabyteFile.txt";
//	char szFileName[] = "H:\\Programming\\WaMM\\ReferenceImplementation\\WaMM\\Hashing.pl";

	pOneMegabyte = malloc(lMegabyte);
	if (NULL!= pOneMegabyte)
	{
		memset(pOneMegabyte, 0, lMegabyte);
		InputFile = fopen(szFileName, "rb");
		if (NULL != InputFile)
		{
			clockStart = clock();

			retVal = Init(&State, 512);
			lNumBytesRead = lMegabyte;
			llTotalBitsHashed = 0;
			while ((SUCCESS == retVal) &&
				   (0 < lNumBytesRead))
			{
				lNumBytesRead = fread(pOneMegabyte, 1, lMegabyte, InputFile);
				if (0 < lNumBytesRead)
				{
					lNumBitsRead = lNumBytesRead * CHAR_BIT;
					retVal = Update(&State, pOneMegabyte, lNumBitsRead);
					llTotalBitsHashed += lNumBitsRead;
				}
			}
			if (SUCCESS == retVal)
			{
				retVal = Final(&State, HashValue);
			}
			clockEnd  = clock();

			printf("Clock Ticks Start: 0x%8.8lX\n", clockStart);
			printf("Clock Ticks End  : 0x%8.8lX\n", clockEnd);
			clockDiff = clockEnd - clockStart;
			printf("Hashed %s in : 0x%8.8lX clock ticks.\n", szFileName, clockDiff);
			printf("At %ld clock ticks/second.\n", CLOCKS_PER_SEC);
			clockDiff /= CLOCKS_PER_SEC;
			printf("%lld bits hashed in, %ld seconds.\n", llTotalBitsHashed, clockDiff);

			fclose(InputFile);
		}
		free(pOneMegabyte);
	}

	return (SUCCESS == retVal);
}

BOOL HashGigabyte()
{
	HashReturn retVal = FAIL;
	hashState State;
	BitSequence HashValue[WaMM_HashLen_MaxBytes];

	BitSequence *pOneMegabyte = NULL;
	BitSequence *pEndOfData = NULL;
	char *szSeed = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
	long lCurrLength;
	long lNextLength;
	const DataLength llGigabyte = 0x40000000;
	const long  lMegabyte = 0x01000000;
	const long  lMegabyte_Bits = lMegabyte * WaMM_BitsPerBitSequence;
	const DataLength llGigabyte_Bits = llGigabyte * WaMM_BitsPerBitSequence;
	const long  lRepeat = (long) (llGigabyte / (DataLength) lMegabyte);
	long lRound;
	clock_t clockStart;
	clock_t clockEnd;
	clock_t clockDiff;
	FILE *OneGigaByteFile; 
	long lNumWritten;

	pOneMegabyte = malloc(lMegabyte);
	if (NULL!= pOneMegabyte)
	{
		memset(pOneMegabyte, 0, lMegabyte);

		lCurrLength = strlen(szSeed);
		memmove(pOneMegabyte, szSeed, lCurrLength);

		do
		{
			pEndOfData = &(pOneMegabyte[lCurrLength]);
			memmove(pEndOfData, pOneMegabyte, lCurrLength);
			lCurrLength *= 2;
			lNextLength = lCurrLength*2;
		}
		while (lNextLength <= lMegabyte);
/*
		OneGigaByteFile = fopen("H:\\Programming\\WaMM\\ReferenceImplementation\\WaMM\\OneGigabyteFile.txt", "wb");
		if (NULL != OneGigaByteFile)
		{
			for( lRound = 0; (lRound < lRepeat); ++lRound)
			{
				lNumWritten = fwrite(pOneMegabyte, lMegabyte, 1, OneGigaByteFile);
				if (1 != lNumWritten)
				{
					assert(FALSE);
				}
			}

			fclose(OneGigaByteFile);
		}
*/
		clockStart = clock();

		retVal = Init(&State, 512);
		for( lRound = 0; (SUCCESS == retVal) && (lRound < lRepeat); ++lRound)
		{
			retVal = Update(&State, pOneMegabyte, lMegabyte_Bits);
		}
		if (SUCCESS == retVal)
		{
			retVal = Final(&State, HashValue);
		}
		clockEnd  = clock();

		printf("Clock Ticks Start: 0x%8.8lX\n", clockStart);
		printf("Clock Ticks End  : 0x%8.8lX\n", clockEnd);
		clockDiff = clockEnd - clockStart;
		printf("One gb Hashed in : 0x%8.8lX clock ticks.\n", clockDiff);
		printf("At %ld clock ticks/second.\n", CLOCKS_PER_SEC);
		clockDiff /= CLOCKS_PER_SEC;
		printf("%lld bits hashed in, %ld seconds.\n", llGigabyte_Bits, clockDiff);

		free(pOneMegabyte);
	}

	return (SUCCESS == retVal);
}

BOOL TestRepeatedHashing()
{
	BOOL bPassed = FALSE;
	HashReturn testResult = SUCCESS;

	int i;
	const int iNumHashings = 24; // 0x10000;
	const int iNumMsgBytes = 512;
	const int iMessagelength = iNumMsgBytes * WaMM_BitsPerBitSequence;
	BitSequence Message[512];
	BitSequence HashValue[WaMM_HashLen_MaxBytes];

	for(i = 0; i < iNumMsgBytes; ++i)
	{
		Message[i] = (BitSequence) i;
	}
	for(i = 0; (SUCCESS == testResult) && (i < iNumHashings); ++i)
	{
		testResult = Hash(224, Message, iMessagelength, HashValue);
	}
	bPassed = (SUCCESS == testResult);

	return bPassed;
}

BOOL TestZeroBitMessages()
{
	BOOL bPassed = FALSE;

	int i;
	int iByte;
	int iNumHashLengths = 1;
	int hashLen[5] = {
			224
		,	256
		,	512
		,	1024
		,	2048
	};
	int iMessagelength;
	int iMaxMessageLength = 513;

	HashReturn testResult;
	const int iMaxMessageBytes = 512;
	BitSequence Message[512];
	BitSequence HashValue[WaMM_HashLen_MaxBytes];
	// hashState State;

	bPassed = TRUE;

	memset(Message, 0, sizeof(Message));

	for(iMessagelength = 1; bPassed && (iMessagelength <= iMaxMessageLength); ++iMessagelength)
	{
		for (i = 0; bPassed && (i < iNumHashLengths); ++i)
		{
			bPassed = FALSE;

			memset(HashValue, 0, sizeof(HashValue));

			testResult = Hash(hashLen[i], Message, iMessagelength, HashValue);
			if (SUCCESS == testResult)
			{
				bPassed = TRUE;
				printf("%3d-bit HashValue for a ZeroBitMessage of %3d bits = ", hashLen[i], iMessagelength); 
				printf("[");
				for(iByte = 0; iByte < hashLen[i] / WaMM_BitsPerByte; ++iByte)
				{
					printf("%2.2X ", HashValue[iByte]);
				}
				printf("].\n");
			}
		}
	}

	return bPassed;
}
